using System;
using System.Collections.Generic;
using System.Text;
using Lizk.SimpleHUD;
using Lizk.DShowPlayer;
using System.Threading;
using System.Diagnostics;
using XNAHUDEngine;

namespace SharpMedia.MDX
{
    public class XNAVideoFile : XNAVideo
    {
        private FilePlayer player;

        public XNAVideoFile(XNAForm form, HUDVideo2 video)
            : base(form, video) 
        {
            player = new FilePlayer(video.SourceUrl);
        }
        

        public override void Unload()
        {
            if (allocator != null)
                allocator.Close();
            allocator = null;
            
                if (player != null && player.State != PlayerState.NotLoaded)
                {
                    if (!video.Closed && (player.State == Lizk.DShowPlayer.PlayerState.Paused || player.State == Lizk.DShowPlayer.PlayerState.Playing))
                    {
                        resumeAfterRestart = player.State == Lizk.DShowPlayer.PlayerState.Playing;
                        this.restart = true;
                        restartPosition = player.Position;
                    }
                    player.Dispose();
                    player = null;

                }




                if (video.Closed)
                    Disposed = true;

        }

        public override void Update()
        {
            if (player != null && player.State != Lizk.DShowPlayer.PlayerState.NotLoaded && player.State != Lizk.DShowPlayer.PlayerState.Disposed)
            {
                video.Updater.SetPosition(player.Position);
                video.Updater.SetDuration(player.Duration);
            } 
            base.Update();
        }

        public override void HandleVideoCommand(HUDVideo2.VideoCommands command, object[] parameters)
        {
            if (player == null)
                return;
            if(allocator != null)
                allocator.Wait = true;
            switch (command)
            {
                case HUDVideo2.VideoCommands.Load:
                    if (player.State == Lizk.DShowPlayer.PlayerState.NotLoaded)
                    {
                        player.StateChanged += new EventHandler<Lizk.DShowPlayer.PlayerEventArgs>(player_StateChanged);
                        player.LanguageChanged += new EventHandler<LanguageEventArgs>(player_LanguageChanged);
                        player.TrackAmountChanged += new EventHandler(player_TrackAmountChanged);
                        player.SetProcAmp += new EventHandler(player_SetProcAmp);
                        
                        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o) { LoadVideo((XNAVideoFile)o); }), this);
                    } break;
                case HUDVideo2.VideoCommands.Play:
                    if (player.State == Lizk.DShowPlayer.PlayerState.Loaded || player.State == Lizk.DShowPlayer.PlayerState.Paused)
                    {
                        player.Play();
                    } 
                    break;
                case HUDVideo2.VideoCommands.Pause:
                    player.Pause();
                    break;
                case HUDVideo2.VideoCommands.Stop:
                    Unload();
                    break;
                case HUDVideo2.VideoCommands.Seek:
                    player.Seek(((TimeSpan)parameters[0]).Ticks, (bool)parameters[1]);
                    break;
                case HUDVideo2.VideoCommands.ChangeSubtitle:
                    player.Subtitle = (int)parameters[0];
                    break;
                case HUDVideo2.VideoCommands.ChangeAudioTrack:
                    player.AudioTrack = (int)parameters[0];
                    break;
                case HUDVideo2.VideoCommands.SetProcAmp:
                    player.Brightness = video.Brightness;
                    player.Contrast = video.Contrast;
                    player.Hue = video.Hue;
                    player.Saturation = video.Saturation;

                    break;
            }
            if (allocator != null)
                allocator.Wait = false;
        }

        void player_SetProcAmp(object sender, EventArgs e)
        {
            video.Updater.SetProcAmp(ConvertProcAmpCaps(player.ProcAmpCaps), player.Brightness, player.StepBrightness, player.MaxBrightness, player.MinBrightness, player.Contrast, player.StepContrast, player.MaxContrast, player.MinContrast, player.Saturation, player.StepSaturation, player.MaxSaturation, player.MinSaturation, player.Hue, player.StepHue, player.MaxHue, player.MinHue);
        }
        private static void LoadVideo(XNAVideoFile cont)
        {
            lock (videoLoadLock)
            {
                try
                {
                    if (cont.Player == null || cont.Player.State == PlayerState.Disposed)
                        return;
                    cont.allocator = new Allocator2(cont.form.GraphicsDevice, cont);
                    cont.Player.Load(cont.form, cont.allocator);

                    // If the video is supposed to restart. We need to seek to where it stopped last time.
                    if (cont.restart)
                    {
                        cont.player.Play();
                        cont.player.Seek(cont.restartPosition.Ticks, true);
                        cont.player.Pause();
                        if (cont.resumeAfterRestart)
                            cont.player.Play();
                        cont.restart = false;
                    }
                    cont.video.Updater.SetDuration(cont.Player.Duration);
                    cont.video.Updater.SetProcAmp(ConvertProcAmpCaps(cont.Player.ProcAmpCaps), cont.Player.Brightness, cont.Player.StepBrightness, cont.Player.MaxBrightness, cont.Player.MinBrightness, cont.Player.Contrast, cont.Player.StepContrast, cont.Player.MaxContrast, cont.Player.MinContrast, cont.Player.Saturation, cont.Player.StepSaturation, cont.Player.MaxSaturation, cont.Player.MinSaturation, cont.Player.Hue, cont.Player.StepHue, cont.Player.MaxHue, cont.Player.MinHue);
                }
                catch
                {
                    cont.Unload();
                    cont.video.Updater.SetState(HUDVideo2.PlayerState.Error);
                }
            }
        }

        private static Player.ProcAmp ConvertProcAmpCaps(HUDVideo2.ProcAmp procamp)
        {
            Player.ProcAmp p = Player.ProcAmp.None;

            if ((procamp & HUDVideo2.ProcAmp.Brightness) == HUDVideo2.ProcAmp.Brightness)
                p |= Player.ProcAmp.Brightness;
            if ((procamp & HUDVideo2.ProcAmp.Contrast) == HUDVideo2.ProcAmp.Contrast)
                p |= Player.ProcAmp.Contrast;
            if ((procamp & HUDVideo2.ProcAmp.Hue) == HUDVideo2.ProcAmp.Hue)
                p |= Player.ProcAmp.Hue;
            if ((procamp & HUDVideo2.ProcAmp.Saturation) == HUDVideo2.ProcAmp.Saturation)
                p |= Player.ProcAmp.Saturation;

            return p;
        }
        private static HUDVideo2.ProcAmp ConvertProcAmpCaps(Player.ProcAmp procamp)
        {
            HUDVideo2.ProcAmp p = HUDVideo2.ProcAmp.None;

            if ((procamp & Player.ProcAmp.Brightness) == Player.ProcAmp.Brightness)
                p |= HUDVideo2.ProcAmp.Brightness;
            if ((procamp & Player.ProcAmp.Contrast) == Player.ProcAmp.Contrast)
                p |= HUDVideo2.ProcAmp.Contrast;
            if ((procamp & Player.ProcAmp.Hue) == Player.ProcAmp.Hue)
                p |= HUDVideo2.ProcAmp.Hue;
            if ((procamp & Player.ProcAmp.Saturation) == Player.ProcAmp.Saturation)
                p |= HUDVideo2.ProcAmp.Saturation;

            return p;
        }
        void player_TrackAmountChanged(object sender, EventArgs e)
        {
            List<Lizk.SimpleHUD.HUDVideo2.TrackIdentifier> tracks = new List<HUDVideo2.TrackIdentifier>();
            foreach (KeyValuePair<int, string> kvp in player.Subtitles)
            {
                Lizk.SimpleHUD.HUDVideo2.TrackIdentifier ti = new HUDVideo2.TrackIdentifier();
                ti.id = kvp.Key;
                ti.name = kvp.Value;
                tracks.Add(ti);
            }
            video.Updater.SetSubtitles(tracks);
            tracks.Clear();
            video.Updater.SetActiveSubtitle(player.Subtitle);

            foreach (KeyValuePair<int, string> kvp in player.AudioTracks)
            {
                Lizk.SimpleHUD.HUDVideo2.TrackIdentifier ti = new HUDVideo2.TrackIdentifier();
                ti.id = kvp.Key;
                ti.name = kvp.Value;
                tracks.Add(ti);
            }
            video.Updater.SetAudiotracks(tracks);
            
            video.Updater.SetActiveAudiotrack(player.AudioTrack);
        }
      

        void player_LanguageChanged(object sender, LanguageEventArgs e)
        {

            if(video.Audiotracks.Count > 0 && video.Audiotracks[video.ActiveAudiotrack].id != e.AudioTrack) 
            {
                video.Updater.SetActiveAudiotrack(e.AudioTrack);
            }
            if (video.Subtitles.Count > 0 && video.Subtitles[video.ActiveSubtitle].id != e.Subtitle)
            {
                video.Updater.SetActiveSubtitle(e.Subtitle);
            }

        }

        void player_StateChanged(object sender, PlayerEventArgs e)
        {
 
            switch (e.NewState)
            {
                case PlayerState.NotLoaded:
                    video.Updater.SetState(HUDVideo2.PlayerState.NotLoaded);
                    break;
                case PlayerState.Loaded:
                    video.Updater.SetState(HUDVideo2.PlayerState.Stopped);
                    break;
                case PlayerState.Playing:
                    video.Updater.SetState(HUDVideo2.PlayerState.Playing);
                    break;
                case PlayerState.Paused:
                    video.Updater.SetState(HUDVideo2.PlayerState.Paused);
                    break;
                case PlayerState.Disposed:
                    video.Updater.SetState(HUDVideo2.PlayerState.NotLoaded);
                    break;
            }


            if (e.NewState != PlayerState.Disposed)
            {
                video.Updater.SetDuration(player.Duration);
                video.Updater.SetPosition(player.Position);
            }

        }


        public override Player Player
        {
            get { return player; }
        }

        public override void Restart()
        {
            if (player == null)
            {
                player = new FilePlayer(video.SourceUrl);
                video.Load();
            }
        }
    }
}
